package com.minimalist.common.config.request;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.minimalist.common.utils.Sm4Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

/**
 * @author 11987
 */
@ControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice{
    private static final Logger log = LoggerFactory.getLogger(DecryptRequestBodyAdvice.class);


    private final java.util.List<String> excludeUrls = new java.util.ArrayList<>(java.util.List.of(
            "/v3/api-docs",
            "/swagger-ui",
            "/swagger-resources",
            "/druid",
            "/actuator",
            "/lindi/api"));

    /**
     * 格式化请求头信息
     */
    private String formatHeaders(org.springframework.http.HttpHeaders headers) {
        if (headers == null || headers.isEmpty()) {
            return "  无请求头信息";
        }
        
        StringBuilder sb = new StringBuilder();
        headers.forEach((key, values) -> {
            sb.append("  ").append(key).append(": ");
            if (values.size() == 1) {
                sb.append(values.get(0));
            } else {
                sb.append(values);
            }
            sb.append("\n");
        });
        return sb.toString().trim();
    }
    
    /**
     * 格式化请求体信息
     */
    private String formatRequestBody(String body) {
        if (StrUtil.isBlank(body)) {
            return "  请求体为空";
        }
        
        try {
            // 尝试格式化JSON
            JSONObject jsonObject = JSONObject.parseObject(body);
            return "  " + jsonObject.toJSONString().replace(",", ",\n  ");
        } catch (Exception e) {
            // 非JSON格式，直接返回原始内容
            return "  " + body;
        }
    }
    
    /**
     * 判断是否为排除的URL
     */
    private boolean isExcludeUrl(String url){
        if (url == null){
            return false;
        }
        return excludeUrls.stream().anyMatch(url::contains);
    }

    @Override
    public boolean supports(@NotNull MethodParameter methodParameter, @NotNull Type targetType,
                            @NotNull Class<? extends HttpMessageConverter<?>> converterType){
        return true;
    }

    @NotNull
    @Override
    public HttpInputMessage beforeBodyRead(
            @NotNull HttpInputMessage inputMessage, @NotNull MethodParameter parameter, @NotNull Type targetType,
            @NotNull Class<? extends HttpMessageConverter<?>> converterType){
        try{
            // 获取请求路径
            String requestPath = inputMessage.getHeaders().getFirst("X-Request-URI");
            if (requestPath == null) {
                // 如果没有自定义头，尝试从其他地方获取路径信息
                // 这里可以根据实际情况调整获取路径的方式
                requestPath = "";
            }
            
            // 检查是否为排除的URL
            if (isExcludeUrl(requestPath)) {
                log.info("URL在排除列表中，跳过解密 {}", requestPath);
                InputStream inputStream = inputMessage.getBody();
                byte[] bodyBytes = inputStream.readAllBytes();
                String data = new String(bodyBytes, StandardCharsets.UTF_8);
                return new DecryptHttpInputMessage(inputMessage, data);
            }
            InputStream inputStream = inputMessage.getBody();
            byte[] bodyBytes = inputStream.readAllBytes();
            String data = new String(bodyBytes, StandardCharsets.UTF_8);
            
            // 格式化日志输出
            log.info("\n=== 请求信息 ===\n" +
                    "请求路径: {}\n" +
                    "请求头信息:\n{}\n" +
                    "请求参数:\n{}\n" +
                    "===============", 
                    requestPath, 
                    formatHeaders(inputMessage.getHeaders()), 
                    formatRequestBody(data));

            // 检查数据是否为空
            if (StrUtil.isBlank(data)){
                log.warn("请求体为空");
                // 返回一个新的HttpInputMessage，包含原始的空数据
                return new DecryptHttpInputMessage(inputMessage, data);
            }

            try{
                JSONObject jsonObject = JSONObject.parseObject(data);
                // 检查是否包含加密数据
                String encryptedData = jsonObject.getString("data");
                if (StrUtil.isNotBlank(encryptedData)){
                    try{
                        String decryptedData = Sm4Util.decrypt(encryptedData);
                        log.info("\n=== 解密信息 ===\n" +
                                "解密后的参数:\n{}\n" +
                                "===============", 
                                formatRequestBody(decryptedData));
                        return new DecryptHttpInputMessage(inputMessage, decryptedData);
                    } catch (Exception e){
                        log.error("解密数据失败: {}", e.getMessage(), e);
                        // 解密失败时返回原始数据的新实例
                        return new DecryptHttpInputMessage(inputMessage, data);
                    }
                }
                // 没有加密数据，返回原始数据的新实例
                return new DecryptHttpInputMessage(inputMessage, data);
            } catch (JSONException e){
                // 非JSON格式数据，记录日志并返回原始数据的新实例
                log.warn("非JSON格式数据: {}", e.getMessage());
                return new DecryptHttpInputMessage(inputMessage, data);
            }
        } catch (Exception e){
            // 捕获所有异常，确保请求处理不中断
            log.error("处理请求体时发生异常: {}", e.getMessage(), e);
            // 发生异常时，创建一个空的HttpInputMessage
            return new DecryptHttpInputMessage(inputMessage, "{}");
        }
    }

    @NotNull
    @Override
    public Object afterBodyRead(
            @NotNull Object body, @NotNull HttpInputMessage inputMessage, @NotNull MethodParameter parameter,
            @NotNull Type targetType,
            @NotNull Class<? extends HttpMessageConverter<?>> converterType){
        return body;
    }

    @Override
    public Object handleEmptyBody(
            Object body, @NotNull HttpInputMessage inputMessage, @NotNull MethodParameter parameter,
            @NotNull Type targetType,
            @NotNull Class<? extends HttpMessageConverter<?>> converterType){
        return body;
    }
}

